package msgcomm.messages;

import java.util.Map;

import msgcomm.Receiver;
import msgcomm.VectorClock;


/**
 * Messaggio di tipo multicast. Offre due campi opzionali: l'insieme dei destinatari
 * e il vector clock.
 */
public class MulticastMessage extends Message implements Comparable<MulticastMessage> {

	private static final long serialVersionUID = 3375648036200876502L;

	/**
	 * Destinatari di questo messaggio.
	 * Opzionale: se non usato e' posto a null
	 */
	private final Map<String, Receiver> destinations;
	/**
	 * Vector clock
	 * Opzionale: se non usato e' posto a null
	 */
	private final VectorClock VC;

	/**
	 * Sequence number: automaticamente incrementato ad ogni creazione di messaggio
	 */
	private static Integer multicastSequenceNumber= 0;

	/**
	 * Il sequence number
	 */
	private final int mcSeqNum;
	

	/**
	 * Crea un messaggio multicast provvisto sia di insieme dei destinatari che
	 * di vector clock
	 * @param sender mittente
	 * @param data il payload
	 * @param destinations mappa dei destinatari (da nickname a receiver)
	 * @param VC vector clock di questo messaggio
	 */
	public MulticastMessage(String sender, Payload data, Map<String, Receiver> destinations, VectorClock VC) {
		super(sender, data);
		this.destinations= destinations;
		this.VC= VC;
		synchronized (MulticastMessage.multicastSequenceNumber) {
			this.mcSeqNum= MulticastMessage.multicastSequenceNumber;
			MulticastMessage.multicastSequenceNumber++;
		}
	}
	
	/**
	 * Crea un messaggio multicast contenente l'insieme dei destinatari ma non
	 * il vector clock
	 * @param sender mittente
	 * @param data il payload
	 * @param destinations mappa dei destinatari (da nickname a receiver)
	 */
	public MulticastMessage(String sender, Payload data, Map<String, Receiver> destinations) {
		this(sender, data, destinations, null);
	}
	
	/**
	 * Crea un messaggio multicast. Insieme dei destinatari e vector clock non sono
	 * usati
	 * @param sender mittente
	 * @param data il payload
	 */
	public MulticastMessage(String sender, Payload data) {
		this(sender, data, null, null);
	}
	
	/**
	 * Ottiene la mappa dei destinatari. Mappa da nickname al corrispondente
	 * recveiver 
	 * @return vedi descrizione
	 */
	public Map<String, Receiver> getDestinations() {
		return destinations;
	}
	
	public VectorClock getVectorClock() {
		return VC;
	}
	

	/**
	 * Estrae il multicast sequence number dal messaggio
	 * @return vedi descrizione
	 */
	public int getMcSeqNum() {
		return mcSeqNum;
	}
	
	@Override
	public String toString() {
		return "MulticastMessage[ " + rawToString() + ", mc#" + mcSeqNum + ", " + destinations.keySet() + ", " + VC + "]";
	}
	
	@Override
	public int compareTo(MulticastMessage o) {
		// TODO ricontrolla implementazione
		String tSender= getSender();
		String oSender= o.getSender();
		if (tSender.compareTo(oSender)<0) {
			return -1;
		} else if (tSender.compareTo(oSender)>0) {
			return 1;
		} else {
			if (this.mcSeqNum < o.mcSeqNum) return -1;
			else if (this.mcSeqNum > o.mcSeqNum) return 1;
			else return 0;
		}
	}
	
	@Override
	public boolean equals(Object anObject) {

        if (this == anObject) {
            return true;
        }
        if (anObject instanceof MulticastMessage) {
        	
        	MulticastMessage anotherMsg = (MulticastMessage) anObject;
        	
        	if (
        		anotherMsg.getSender().equals(this.getSender()) &&
        		anotherMsg.getMcSeqNum() == this.getMcSeqNum()
        	) {
        		return true;
        	} else {
        		return false;
        	}
        		
        }
        return false;
	}
}
